﻿using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Finances.Repository;
using mozhi.smarterp.Finance.Querys;
using Mozhi.Abp.Domain.BasicData;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;

namespace mozhi.smarterp.Finance.Accounts
{
    public class AccountAppService : FinanceAppService, IAccountAppService
    {
        private IAccountRepository _accountRepository;
        private IAccountDimensionRepository _dimensionRepository;
        private AccountManager _accountManager;
        private IAccountBalanceRepository _accountBalanceRepository;
        private IJournalRepository _journalRepository;
        private ICustomerRepository _customerRepository;
        private ISupplierRepository _supplierRepository;
        private IEmployeeRepository _employeeRepository;
        private IExpenseItemRepository _expenseItemRepository;
        private IProductRepository _productRepository;
        public AccountAppService(IAccountRepository accountRepository, IAccountDimensionRepository dimensionRepository,
            IAccountBalanceRepository accountBalanceRepository,IJournalRepository journalRepository,
            ICustomerRepository customerRepository, ISupplierRepository supplierRepository, 
            IEmployeeRepository employeeRepository,  IProductRepository productRepository,IExpenseItemRepository expenseItemRepository ,
            AccountManager accountManager, IDataAssociationRepository dataAssociationRepository) : base(dataAssociationRepository)
        {
            _accountRepository = accountRepository;
            _dimensionRepository = dimensionRepository;
            _accountManager = accountManager;
            _accountBalanceRepository = accountBalanceRepository;
            _journalRepository = journalRepository;
            _customerRepository = customerRepository;
            _supplierRepository = supplierRepository;
            _employeeRepository = employeeRepository;
            _productRepository = productRepository;
            _expenseItemRepository = expenseItemRepository;
        }

        public async Task<AccountDto> GetAsync(Guid id)
        {
            var account = await _accountRepository.GetAsync(id);

            if (account == null)
                throw new UserFriendlyException($"科目:{id}不存在", "100000");

            var result = ObjectMapper.Map<Account, AccountDto>(account);

            await LoadDimensionItemsAsync(new List<AccountDto> { result });

            return result;
        }

        public async Task<List<AccountDto>> GetListAsync(AccountQuery query)
        {
            //var accounts = await _accountRepository.FindAsync(query);

            //if (accounts.Count == 0)
            //    return new List<AccountDto>();

            //var result = ObjectMapper.Map<List<Account>, List<AccountDto>>(accounts);

            //await LoadDimensionItemsAsync(result);

            //return result;
            throw new NotImplementedException();
        }

        public async Task<AccountDto> CreateAsync(AccountCreateDto dto)
        {
            var dimensionItems = await GetDimensionItems(dto.DimensionItems);

            var tuples = await _accountManager.CreateAsync(dto.ParentId, dto.Code, dto.Name, dto.AccountType,
                dto.Direction, dto.IsFundAccount, dto.BankAccountId, dimensionItems);

            var account = tuples.Item1;
            var parent = tuples.Item2;
            var balances = tuples.Item3;
            var journals = tuples.Item4;
            var basedataDict = tuples.Item5;

            account = await _accountRepository.InsertAsync(account);

            if (parent != null)
                await _accountRepository.UpdateAsync(parent);

            if (balances.Count > 0)
            {
                var deleteBalances = balances.Where(x => x.AccountId == parent.Id).ToList();

                if (deleteBalances.Count > 0)
                    await _accountBalanceRepository.DeleteAsync(deleteBalances);

                var insertOrUpdateBalances = balances.Where(x => x.AccountId == account.Id).ToList();

                if (insertOrUpdateBalances.Count == 0)
                    await _accountBalanceRepository.InsertOrUpdateAsync(insertOrUpdateBalances);
            }

            if (journals.Count > 0)
                await _journalRepository.UpdateAsync(journals);

            //if (basedataDict.Keys.Count > 0)
            //await UpdateBaseDataAsync(basedataDict);

            return ObjectMapper.Map<Account, AccountDto>(account);
        }


        public async Task<AccountDto> UpdateAsync(AccountUpdateDto dto)
        {
            var dimensionItems = await GetDimensionItems(dto.DimensionItems);

            var account = await _accountManager.UpdateAsync(dto.Id, dto.Code, dto.Name, dto.Direction, dto.Activated, dto.BankAccountId, dto.IsForeignCurrency , dimensionItems);

            account = await _accountRepository.UpdateAsync(account);

            return ObjectMapper.Map<Account, AccountDto>(account);
        }

        public async Task DeleteAsync(Guid id)
        {
            var tuples = await _accountManager.DeleteAsync(id);

            var account = tuples.Item1;
            var parent = tuples.Item2;
            var balances = tuples.Item3;
            var journals = tuples.Item4;
            var basedataDict = tuples.Item5;

            await _accountRepository.DeleteAsync(account);

            if (parent != null)
                await _accountRepository.UpdateAsync(parent);

            if (balances.Count > 0)
            {
                var deleteBalances = balances.Where(x => x.AccountId == account.Id).ToList();

                if (deleteBalances.Count > 0)
                    await _accountBalanceRepository.DeleteAsync(deleteBalances);

                var insertOrUpdateBalances = balances.Where(x => x.AccountId == parent.Id).ToList();

                if (insertOrUpdateBalances.Count == 0)
                    await _accountBalanceRepository.InsertOrUpdateAsync(insertOrUpdateBalances);
            }

            if (journals.Count > 0)
                await _journalRepository.UpdateAsync(journals);

            //if (basedataDict.Keys.Count > 0)
            //    await UpdateBaseDataAsync(basedataDict);
        }

        public async Task LoadDefaultAccountAsync(AccountingStandardType accountingStandard)
        {
            //var defaultAccounts = await _accountRepository.GetDefaultAccounts(accountingStandard);

            //var oldAccounts = await _accountRepository.GetListAsync();

            //if (oldAccounts.Count > 0)
            //    await _accountRepository.DeleteAsync(oldAccounts);

            //await _accountRepository.InsertAsync(defaultAccounts);
            throw new NotImplementedException();
        }

        #region 
        private async Task<List<AccountDimensionItem>> GetDimensionItems(List<AccountDimensionItemCreateDto> items)
        {
            var result = new List<AccountDimensionItem>();

            if (items == null || items.Count == 0)
                return result;

            foreach (var item in items)
            {
                var dimensionItem = await _accountManager.CreateDimensionItem(item.DimensionId, item.IsRequire, item.Activated);

                result.Add(dimensionItem);
            }

            return result;
        }

        private async Task LoadDimensionItemsAsync(List<AccountDto> accounts)
        {
            if (accounts == null || accounts.Count == 0)
                return;

            var dimensionIds = accounts.Where(x => x.DimensionItems != null).SelectMany(x => x.DimensionItems).Select(x => x.DimensionId).ToList();

            if (dimensionIds.Count == 0)
                return;

            var dimensions = await _dimensionRepository.FindAsync(new PageQuery() { Ids = dimensionIds, PageIndex = 1, PageSize = int.MaxValue });

            if (dimensions.Count == 0)
                return;

            accounts.ForEach(account =>
            {
                if (account.DimensionItems != null && account.DimensionItems.Count > 0)
                {
                    account.DimensionItems.ForEach(dimensionItem =>
                    {
                        var matchDimension = dimensions.FirstOrDefault(x => x.Id == dimensionItem.DimensionId);

                        dimensionItem.DimensionName = matchDimension?.Name;
                        dimensionItem.DataSourceType = matchDimension == null ? default : matchDimension.DataSourceType;
                        dimensionItem.TagId = matchDimension?.TagId;
                    });
                }
            });
        }


        //private async Task UpdateBaseDataAsync(Dictionary<string, List<object>> basedataDict)
        //{
        //    foreach (var key in basedataDict.Keys)
        //    {
        //        var values = basedataDict[key];

        //        if (values == null || values.Count == 0)
        //            continue;

        //        if (key == nameof(Customer))
        //        {
        //            foreach (var value in values)
        //            {
        //                var customer = value as Customer;

        //                await _customerRepository.UpdateAsync(customer);
        //            }
        //        }
        //        else if (key == nameof(Supplier))
        //        {
        //            foreach (var value in values)
        //            {
        //                var supplier = value as Supplier;

        //                await _supplierRepository.UpdateAsync(supplier);
        //            }
        //        }
        //        else if (key == nameof(ThirdParty))
        //        {
        //            foreach (var value in values)
        //            {
        //                var entity = value as ThirdParty;

        //                await _thirdPartyRepository.UpdateAsync(entity);
        //            }
        //        }
        //        else if (key == nameof(Employee))
        //        {
        //            foreach (var value in values)
        //            {
        //                var entity = value as Employee;

        //                await _employeeRepository.UpdateAsync(entity);
        //            }
        //        }
        //        else if (key == nameof(ExpenseItem))
        //        {
        //            foreach (var value in values)
        //            {
        //                var entity = value as ExpenseItem;

        //                await _expenseItemRepository.UpdateAsync(entity);
        //            }
        //        }
        //        else if (key == nameof(Product))
        //        {
        //            foreach (var value in values)
        //            {
        //                var entity = value as Product;

        //                await _productRepository.UpdateAsync(entity);
        //            }
        //        }
        //    }
        //}

        #endregion
    }
}
